package com.citywithincity.redis.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

public class RedisMapper {
	private static Map<Class<?>, Schema<?>> map = new HashMap<Class<?>, Schema<?>>();
	
	@SuppressWarnings("unchecked")
	public static <T> Schema<T> getSchema(Class<T> clazz){
		Schema<T> schema = (Schema<T>) map.get(clazz);
		if(schema==null){
			synchronized (map) {
				schema = (Schema<T>) map.get(clazz);
				if(schema==null){
					schema =  RuntimeSchema.getSchema(clazz);
					map.put(clazz,schema);
				}
			}
		}
		return schema;
	}
	
	
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static byte[] toBytes(Object value){
		Schema schema = getSchema(value.getClass());
		return ProtostuffIOUtil.toByteArray(value, schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
	}
	
	
	public static <T> T toObject(byte[] bytes,Class<T> clazz){
		Schema<T> schema = (Schema<T>) getSchema(clazz);
		T message= schema.newMessage();
		ProtostuffIOUtil.mergeFrom(bytes, message, schema);
		return message;
	}



	public static <T> List<T> toList(List<byte[]> list, Class<T> clazz) {
		if(list.size()==0)return null;
		Schema<T> schema = (Schema<T>) getSchema(clazz);
		List<T> result = new ArrayList<T>(list.size());
		for(int i=0 , c = list.size(); i < c; ++i){
			byte[] bytes = list.get(i);
			T message= schema.newMessage();
			ProtostuffIOUtil.mergeFrom(bytes, message, schema);
			result.add(message);
		}
		return result;
	}


	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static byte[][] toListBytes(List<?> list, Class<?> clazz) {
		Schema schema = getSchema(clazz);
		byte[][] result = new byte[list.size()][];
		for(int i=0 , c = list.size(); i < c; ++i){
			Object value = list.get(i);
			byte[] bytes = ProtostuffIOUtil.toByteArray(value, schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
			result[i] = bytes;
		}
		return result;
	}
}
